﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.IO;


namespace PPC_emulator
{
    public enum MemoryViewMode
    {
        Hex,
        ASCII,
        ANSI,
        Unicode
    }

    class MemoryViewer
    {
        private DataGridView gView;
        private TextBox pokeAddress;
        private TextBox pokeValue;
        private Label fpValue;
        private UInt32 cAddress;
        private UInt32 selAddress;
        private MemoryViewMode PViewMode;
        private RAM ram;

        private int oldCol = 1;
        private int oldRow = 0;

        public UInt32 address
        {
            get
            {
                return cAddress;
            }
            set
            {
                cAddress = value & 0xFFFFFFFC;
            }
        }

        public UInt32 selectedAddress
        {
            get
            {
                return selAddress;
            }
        }


        public MemoryViewMode viewMode
        {
            get
            {
                return PViewMode;
            }
            set
            {
                PViewMode = value;
            }
        }

        public MemoryViewer(UInt32 initAddress,DataGridView UGView,
            TextBox UPokeAddress,TextBox UPokeValue,Label UFPValue, RAM ram)
        {
            cAddress = initAddress;
            gView = UGView;
            pokeAddress = UPokeAddress;
            pokeValue = UPokeValue;
            fpValue = UFPValue;
            gView.CellClick += CellClick;
            gView.SelectionChanged += CellSelectionChange;
            this.ram = ram;

        }

        private UInt32 ReadStream(Stream input)
        {
            Byte[] buffer = new Byte[4];
            input.Read(buffer, 0, 4);
            return (UInt32)ByteSwap.Swap(BitConverter.ToUInt32(buffer, 0));
        }

        public void Update()
        {
            gView.Rows.Clear();
            UInt32 sAddress = cAddress & 0xFFFFFF00;
            UInt32 offset = cAddress - sAddress;
            MemoryStream miniDump = new MemoryStream(ram.getMiniStream(sAddress - 0x80000000));
            //gecko.Dump(sAddress, sAddress + 0x100, miniDump);

            gView.Rows.Add(16);
            miniDump.Seek(0, SeekOrigin.Begin);
            UInt32 value,bValue;
            Byte[] buffer = new Byte[4];
            Byte bInput;
            UInt16 hwInput;
            UInt32 pValue = 0;
            for (int i = 0; i < 16; i++)
            {
                gView.Rows[i].Cells[0].Value = GlobalFunctions.toHex(sAddress + i * 16);
                for (int j = 1; j < 5; j++)
                {
                    miniDump.Read(buffer,0,4);
                    bValue = BitConverter.ToUInt32(buffer,0);
                    value = bValue;
                    if (i * 0x10 + (j - 1) * 4 == offset)
                        pValue = value;
                    if (PViewMode == MemoryViewMode.Hex)
                    {
                        gView.Rows[i].Cells[j].Value = GlobalFunctions.toHex(value);
                    }
                    else if (PViewMode == MemoryViewMode.ASCII)
                    {
                        String cellV = "";
                        for (int k = 0; k < 4; k++)
                        {
                            bInput = buffer[k];
                            if (bInput > 0x20 && bInput < 0x7F)
                                cellV += " "+(char)bInput;
                            else
                                cellV += " .";
                        }
                        gView.Rows[i].Cells[j].Value = cellV;
                    }
                    else if (PViewMode == MemoryViewMode.ANSI)
                    {
                        String cellV = "";
                        for (int k = 0; k < 4; k++)
                        {
                            bInput = buffer[k];
                            if (bInput > 0x20 && bInput != 0x7F)
                                cellV += " " + (char)bInput;
                            else
                                cellV += " .";
                        }
                        gView.Rows[i].Cells[j].Value = cellV;
                    }
                    else if (PViewMode == MemoryViewMode.Unicode)
                    {
                        String cellV = "";
                        for (int k = 0; k < 2; k++)
                        {
                            hwInput = (UInt16)(buffer[k*2] << 8 + buffer[k*2+1]);
                            if (hwInput > 0x20 && hwInput != 0x7F)
                                cellV += "   " + (char)hwInput;
                            else
                                cellV += "   .";
                        }
                        gView.Rows[i].Cells[j].Value = cellV;
                    }
                }
            }
            oldRow = (int)offset / 0x10;
            oldCol = (int)(offset & 0xC) / 4+1;
            gView.Rows[oldRow].Cells[oldCol].Selected = true;
            
            pokeAddress.Text = GlobalFunctions.toHex(cAddress);
            pokeValue.Text = GlobalFunctions.toHex(pValue);
            fpValue.Text = GlobalFunctions.UIntToSingle(pValue).ToString("G6");

        }

        private void CellClick(object sender, DataGridViewCellEventArgs e)
        {
            //
        }


        private void CellSelectionChange(object sender, EventArgs e)
        {
            UInt32 sAddress = cAddress & 0xFFFFFF00;
            if (gView.SelectedCells.Count > 0)
            {
                int col = gView.SelectedCells[0].ColumnIndex;
                int row = gView.SelectedCells[0].RowIndex;
                if (col == 0)
                {
                    gView.Rows[oldRow].Cells[oldCol].Selected = true;
                }
                else
                {
                    oldCol = col;
                    oldRow = row;
                    UInt32 addr = (UInt32)(sAddress + row * 16 + (col - 1) * 4);
                    selAddress = addr;
                    pokeAddress.Text = GlobalFunctions.toHex(addr);
                    UInt32 locValue = ram.getValue32(addr - 0x80000000);         //gecko.peek(addr);
                    pokeValue.Text = GlobalFunctions.toHex(locValue);
                    fpValue.Text = GlobalFunctions.UIntToSingle(locValue).ToString("G6");
                }
            }
        }

        public void poke()
        {
            UInt32 address = UInt32.Parse(pokeAddress.Text, System.Globalization.NumberStyles.HexNumber);
            UInt32 value = UInt32.Parse(pokeValue.Text, System.Globalization.NumberStyles.HexNumber);
            ram.setAddress32(address - 0x80000000, value);
        }
    }
}
